# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1069.45.1 -> 1.1069.45.2 # include/linux/hugetlb.h 1.2 -> 1.3 # arch/ia64/mm/hugetlbpage.c 1.3 -> 1.4 # fs/hugetlbfs/inode.c 1.4 -> 1.5 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/09/30 khalid@fc.hp.com 1.1069.44.2 # ia64: do_settimeofday: fix compensation for lost ticks # -------------------------------------------- # 03/09/30 davidm@tiger.hpl.hp.com 1.1069.44.3 # ia64: Mark access_ok() as likely to succeed (as is done in x86 tree). # -------------------------------------------- # 03/09/30 len.brown@intel.com 1.1063.44.17 # [ACPI] acpi4asus-0.24a-0.25-2.4 (Karol Kozimor) # -------------------------------------------- # 03/09/30 len.brown@intel.com 1.1063.44.18 # [ACPI] acpi4asus-0.25-0.26 (Karol Kozimor) # -------------------------------------------- # 03/09/30 len.brown@intel.com 1.1069.1.71 # Merge intel.com:/home/lenb/bk/linux-acpi-test-2.4.22 # into intel.com:/home/lenb/bk/linux-acpi-test-2.4.23 # -------------------------------------------- # 03/09/30 stern@rowland.harvard.edu 1.1069.33.19 # [PATCH] USB: unusual_devs.h update # -------------------------------------------- # 03/09/30 kaos@sgi.com 1.1069.44.4 # ia64: mca_asm.h documentation fixes # # Documentation fix for mca_asm.h. Refer to the released Intel manual # and correct a field name. No functional changes. # -------------------------------------------- # 03/09/30 kenneth.w.chen@intel.com 1.1069.45.2 # HUGETLBFS: quota bugfix and sync to 2.6. # # Here is a bug fix patch relative to latest Bjorn's 2.4 ia64 kernel tree. # Mainly sync up hugetlbfs code w.r.t latest 2.6. # # Hugetlb file system quota was incorrectly taken on every mmap even for # the case that huge pages has been already allocated on the file inode. # This results in taxing the same hugepage multiple times and causing mmap # to fail on existing file when quota mistakenly runs out. This patch also # fixes file size to account holes. # -------------------------------------------- # diff -Nru a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c --- a/arch/ia64/mm/hugetlbpage.c Thu Oct 9 15:20:21 2003 +++ b/arch/ia64/mm/hugetlbpage.c Thu Oct 9 15:20:21 2003 @@ -262,18 +262,19 @@ + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); page = find_get_page(mapping, idx); if (!page) { - loff_t i_size; + /* charge the fs quota first */ + if (hugetlb_get_quota(mapping)) { + ret = -ENOMEM; + goto out; + } page = alloc_hugetlb_page(); if (!page) { + hugetlb_put_quota(mapping); ret = -ENOMEM; goto out; } add_to_page_cache(page, mapping, idx); unlock_page(page); - i_size = (loff_t)(idx + 1) * HPAGE_SIZE; - if (i_size > inode->i_size) - inode->i_size = i_size; - } set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); } diff -Nru a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c --- a/fs/hugetlbfs/inode.c Thu Oct 9 15:20:21 2003 +++ b/fs/hugetlbfs/inode.c Thu Oct 9 15:20:21 2003 @@ -139,8 +139,7 @@ { struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; - struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb); - loff_t len; + loff_t len, vma_len; int ret; if (vma->vm_start & ~HPAGE_MASK) @@ -155,17 +154,7 @@ if (vma->vm_start < (REGION_HPAGE << REGION_SHIFT)) return -EINVAL; #endif - len = (loff_t)(vma->vm_end - vma->vm_start); - if (sbinfo->free_blocks >= 0) { /* Check if there is any size limit. */ - spin_lock(&sbinfo->stat_lock); - if ((len >> HPAGE_SHIFT) <= sbinfo->free_blocks) { - sbinfo->free_blocks -= (len >> HPAGE_SHIFT); - spin_unlock(&sbinfo->stat_lock); - } else { - spin_unlock(&sbinfo->stat_lock); - return -ENOMEM; - } - } + vma_len = (loff_t)(vma->vm_end - vma->vm_start); down(&inode->i_sem); @@ -173,15 +162,11 @@ vma->vm_flags |= VM_HUGETLB | VM_RESERVED; vma->vm_ops = &hugetlb_vm_ops; ret = hugetlb_prefault(mapping, vma); + len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); + if (ret == 0 && inode->i_size < len) + inode->i_size = len; up(&inode->i_sem); - /* If the huge page allocation has failed then increment the free_blocks. */ - if ((ret != 0) && (sbinfo->free_blocks >= 0)) { - spin_lock(&sbinfo->stat_lock); - sbinfo->free_blocks += (len >> HPAGE_SHIFT); - spin_unlock(&sbinfo->stat_lock); - } - return ret; } @@ -261,7 +246,6 @@ void truncate_hugepages(struct inode *inode, struct address_space *mapping, loff_t lstart) { - struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); unsigned long start = lstart >> HPAGE_SHIFT; unsigned long next; unsigned long max_idx; @@ -277,13 +261,8 @@ page_cache_release(page); truncate_huge_page(mapping, page); unlock_page(page); - if (sbinfo->free_blocks >= 0) { - spin_lock(&sbinfo->stat_lock); - sbinfo->free_blocks ++; - spin_unlock(&sbinfo->stat_lock); - } + hugetlb_put_quota(mapping); } - } static void hugetlbfs_delete_inode(struct inode *inode) @@ -717,6 +696,36 @@ out_dentry: dput(dentry); return ERR_PTR(error); +} + +int hugetlb_get_quota(struct address_space * mapping) +{ + int ret = 0; + struct hugetlbfs_sb_info *sbinfo = + HUGETLBFS_SB(mapping->host->i_sb); + + if (sbinfo->free_blocks > -1) { + spin_lock(&sbinfo->stat_lock); + if (sbinfo->free_blocks > 0) + sbinfo->free_blocks--; + else + ret = -ENOMEM; + spin_unlock(&sbinfo->stat_lock); + } + + return ret; +} + +void hugetlb_put_quota(struct address_space *mapping) +{ + struct hugetlbfs_sb_info *sbinfo = + HUGETLBFS_SB(mapping->host->i_sb); + + if (sbinfo->free_blocks > -1) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_blocks++; + spin_unlock(&sbinfo->stat_lock); + } } static int __init init_hugetlbfs_fs(void) diff -Nru a/include/linux/hugetlb.h b/include/linux/hugetlb.h --- a/include/linux/hugetlb.h Thu Oct 9 15:20:21 2003 +++ b/include/linux/hugetlb.h Thu Oct 9 15:20:21 2003 @@ -74,6 +74,8 @@ extern struct file_operations hugetlbfs_file_operations; extern struct vm_operations_struct hugetlb_vm_ops; struct file *hugetlb_zero_setup(size_t); +int hugetlb_get_quota(struct address_space *mapping); +void hugetlb_put_quota(struct address_space *mapping); static inline int is_file_hugepages(struct file *file) { @@ -89,6 +91,8 @@ #define is_file_hugepages(file) 0 #define set_file_hugepages(file) BUG() #define hugetlb_zero_setup(size) ERR_PTR(-ENOSYS) +#define hugetlb_get_quota(mapping) 0 +#define hugetlb_put_quota(mapping) 0 #endif /* !CONFIG_HUGETLBFS */